#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef MTRACE
#include <mcheck.h>
#endif

/* Structure for a single card */
typedef struct {
    char n;	/* Rank 1-13 */
    char s;	/* Suit 0-3 */
    int faceup;	/* Is the card faceup? Only used where it matters */
} Card;

/* Structure for a stack of cards */
typedef struct st_stack {
    int n;	/* number of cards in stack */
    int size;	/* Allocated memory for stack */
    Card **c;	/* Array of pointers to cards */
    int type;	/* FOUND,TABLEAU, etc */
    int tid;	/* index among those */
    /* function telling if the given card may be inserted in this stack */
    int (*mayInsert)(struct st_stack *dst, Card *card, int len,
	    struct st_stack *src);
    /* function returning the first move that can be made from this stack */
    int (*firstMove)(struct st_stack *stack, int *index1, int *len);
    /* function returning the next move that can be made from this stack */
    int (*nextMove)(struct st_stack *stack, int *index1, int *len);
    /* function called after removing cards from the stack */
    void (*postMove)(struct st_stack *stack);

} Stack;

#define SPADE   0
#define HEART   1
#define CLUB    2
#define DIAMOND 3

#define FOUND 0
#define WASTE 1
#define STOCK 2
#define BOUQUET 3
#define TABLEAU 4
#define BITABLEAU 5
#define COURSE 6
#define TYPECHAR "FWSBTTF"

/* Suit match rules */
#define S_NONE 0
#define S_SAMESUIT 1
#define S_SAMECOLOR 2
#define S_DIFFCOLOR 3
#define S_DIFFSUIT 4
#define S_ANYTHING 5

typedef struct st_move {
    int type;	/* type: MTYPE_* value */
    int srcid;  /* Id of source stack */
    int srci;   /* Old index of first card in source stack */
    int len;    /* Number of cards moved */
    int dstid;  /* Id of destination stack - alway place cards on top */
    int flip;   /* Moving this caused us to flip next card on source stack */
    int score;  /* Score for this move. Lower is better */
    int reverse;/* stack should be reversed as we move it */
    int btop;   /* Old bouquet top value for moves from a bouquet */
    struct st_move *prev;  /* Pointer to previous move, NULL if none */
    struct st_move *alt;   /* Pointer to (next) alternate move */
} Move;

/* Move Types */
#define MTYPE_STD 0	/* Your basic card or stack move */
#define MTYPE_DEAL 1	/* Deal a card or cards from stock */
#define MTYPE_REDEAL 2	/* Pickup and Redeal tableau */

extern int nstock, nwaste, ntableau, nbouquet, nfound, nbitableau, ncourse;

/* Global variable declarations */
extern int ndeck, nsuit, npip, ncolor, suitcolor[], nstacks, ncard;
extern char *suitletter, *rankletter;
extern int verbose, nsrc, ndst, runcnt;
extern Stack *stacks;
extern int srclist[], dstlist[];
extern int *rankdata;
extern int unixrand;
extern Card *deck;

/* Global function declarations */

void makeDeck(void);
void cleanDeck(void);
Stack *shuffle(void);
Card *extractCard(Stack *shuf, int n, int s);
Stack *sorted(void);
Stack *revsorted(void);
Card *topStack(Stack *stack);
Card *popStack(Stack *stack);
void pushStack(Stack *stack, Card *card);
void appendStack(Stack *to, Stack *from, int reverse);
void removeStack(Stack *s, int index1, int len);
void insertStack(Stack *s, int index1, int len, Card **c, int reverse);
Stack *allocStack(int n);
void freeStack(Stack *st);
void expandStack(Stack *st, int n, int pad);
char *cardname(Card *c);
void printCard(FILE *f, Card *c);
void printStack(FILE *f, char *label, Stack *st);
int newStack(int type, int tid, int initsize,
    int (*mayInsert)(Stack *dst, Card *card, int len, Stack *src),
    int (*firstMove)(Stack *stack, int *index1, int *len),
    int (*nextMove) (Stack *stack, int *index1, int *len),
    void (*postMove)(struct st_stack *stack) );
void cleanStacks(void);
int suitmatch(int rule, int s1, int s2);
int rankmatch(int step, int base, int r1, int r2);
int checkseq(int suitrule, int rankrule, int base, Card **c, int len);
Stack *dupStacks(Stack *orig, int norig);
void cleanDup(Stack *stks);
void copyStacks(Stack *copy, Stack *orig, int norig, int isnew);

Move *newMove(int type, int srcid, int srci, int len, int dstid, int score, int flip);

void riffle(Stack *old, Stack *new, int a);
void overhand(Stack *old, Stack *new, int oneoverp, int n);
void cutdeck(Stack *old, Stack *new);

int visitedState(char *state);
void cleanVisited();
unsigned int nVisited();

void randseed(char *seed);
int randint(int n);
